package server_client;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;

import java.io.IOException;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import java.net.UnknownHostException;
import java.util.Queue;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;

/**
 * Klasa "Client" odpowiada za utworzenie połączenia z serwerem oraz za wysyłanie danych do serwera.
 * @author Piotr Jasiak, Szymon Wawrzyniak, Artur Angiel
 */
public class Client {

    private ObjectInputStream in;
    private ObjectOutputStream out;
    private Object received;
    private Thread receivedThread;
    private SSLSocket sslsocket;
    private Object receivedObject;
    private Queue<Object> receivedObjects;

    /**
     * Pusty konstruktor.
     * 
     */
    public Client() {
    }

    /**
     * Metoda "connect" odpowiada za utworzenie i utrzymanie połączenia.
     * @param address Adres IP serwera.
     * @param port Port, na którym serwer nasłuchuje.
     * @return 0 - brak błędu; -1 - nieznany serwer; -2 - błąd we/wy;
     */
    public int connect(String address, int port) {

	try {

	    System.setProperty("javax.net.ssl.trustStore", "src/server_client/certyfikat");
	    // System.setProperty("javax.net.ssl.keyStorePassword","inzopr");


	    SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
	    sslsocket = (SSLSocket) sslsocketfactory.createSocket(address, port);



	    out = new ObjectOutputStream(new BufferedOutputStream(sslsocket.getOutputStream()));

	    //Utworzenie oddzielnego wątka do odbierania objektów
	    receivedThread = new Thread(new receivedWorker(sslsocket));
	    receivedThread.start();


	} catch (UnknownHostException ex) {
	    Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
	    return -1;
	} catch (IOException ex) {
	    Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
	    return -2;
	}

	return 0;
    }

    public int disconnect() {

	receivedThread.stop();

	return 0;
    }

    /**
     * Metoda "send" odpowiada za wysłanie obiektu.
     * @param obj Obiekt do wysłania.
     */
    public void send(Object obj) throws IOException {

	out.writeObject(obj);
	out.flush();
	out.reset();
    }
    public Object getFromQueue() {
        Object tmp; 
        tmp = receivedObjects.peek();
        receivedObjects.poll();
        return tmp;
}

    /**
     * Metoda "receive" służy do zwrócenia odebranego objektu
     * @return Object Odebrany objekt
     */
    public void receive() {
          receivedObjects.add(receivedObject);
    }

    /**
     * Klasa która jest używana do stworzenia oddzielnego wątku, którego zadaniem jest
     * odbieranie danych z serwera
     */
    class receivedWorker implements Runnable {

	private SSLSocket server;

	public receivedWorker(SSLSocket socket) {
	    this.server = socket;
	}

	public void run() {
	    try {
		in = new ObjectInputStream(new BufferedInputStream(server.getInputStream()));
	    } catch (IOException ex) {
		//Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
	    }
	    try {


		while ((receivedObject = in.readObject()) != null) {
		    //System.out.println(receivedObject.napis);
		}
	    } catch (IOException ex) {
		//Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
	    } catch (ClassNotFoundException ex) {
		//Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
	    }
	}
    }
}